/**
 * @File:  fLCD3bSDCC.h
 * @Author: Miguel
 *
 * @brief 
 * basado en la libreria publicada en el foro de ucontrol por Suky
 * Para C18 no define una licencia
 * http://www.ucontrol.com.ar/forosmf/tutoriales-guias-y-cursos-en-ucontrol/tutorial-mplab-c18-desde-0/15/
 * y en la libreria publicada por Felixls en su blog
 * con licencia Creative Commons 3.0
 * http://dl.dropbox.com/u/24861335/Felixls/DigitalPowerSupply/DigitalPowerSupply-src.zip
 * encontrados en lcd.h y lcd.c
 * se requiere ademas de la libreria hecha por  Ervin Jung (2010)
 *  para los retardos con licencia GPL2.0
 * http://junif.hu/mop/programok/simple_delay.h
 * Esta libreria no utiliza el PIN RW
 * @date Created on 29 de agosto de 2012, 03:47 AM
 */

#ifndef fLCD3bSDCC_h
#define fLCD3bSDCC_h
//

/**
 * @brief
 * Definición de las terminales a utilizar
 * LATxbits se usa para escribir al puerto x
 * PORTxbits se usa para leer el estado del puerto
 * TRISxbits se utliza para configurar el puerto
 */
#define LCD_DAT    LATAbits.LATA2            ///@brief salida
#define LCD_CK      LATAbits.LATA1            ///salida
#define LCD_E      LATAbits.LATA0            ///salida

#define E_PIN  LCD_E
#define CK_PIN  LCD_CK
#define DAT_PIN LCD_DAT

#define confLCD_DAT    TRISAbits.TRISA2            ///salida
#define confLCD_CK      TRISAbits.TRISA1            ///salida
#define confLCD_E      TRISAbits.TRISA0            ///salida

#define TRIS_E  confLCD_E
#define TRIS_CK confLCD_CK
#define TRIS_DAT confLCD_DAT


/**
 * \verbatim
 * Definiciones para configurar el LCD
 *
 * Actualizacion: Esta actualizacion es
  19 de mayo de 2011, modifico la libreria para poder usarla con la de hunif
  simple_delay.h
  * Se agregan #define LCD_LINEA 3 y LCD_LINEA_4 para usar una lcd de 4 lineas
  * Se agrega la funcion lcd_gotoxy, adaptada de la version de CCS
  * El encabezado de tu archivo main debe ser el siguiente

  code char at __CONFIG1L CONFIG1L = _PLLDIV_DIVIDE_BY_5__20MHZ_INPUT__1L & _CPUDIV__OSC1_OSC2_SRC___1__96MHZ_PLL_SRC___2__1L & _USBPLL_CLOCK_SRC_FROM_96MHZ_PLL_2_1L;
code char at __CONFIG1H CONFIG1H = _OSC_HS__HS_PLL__USB_HS_1H & _FCMEN_ON_1H & _IESO_ON_1H;
code char at __CONFIG2L CONFIG2L = _PUT_ON_2L & _BODEN_ON_2L & _BODENV_4_2V_2L & _VREGEN_ON_2L;
code char at __CONFIG2H CONFIG2H = _WDT_DISABLED_CONTROLLED_2H & _WDTPS_1_32768_2H;
code char at __CONFIG3H CONFIG3H = _CCP2MUX_RC1_3H & _PBADEN_PORTB_4_0__CONFIGURED_AS_DIGITAL_I_O_ON_RESET_3H & _LPT1OSC_ON_3H & _MCLRE_MCLR_OFF_RE3_ON_3H;
code char at __CONFIG4L CONFIG4L = _STVR_ON_4L & _LVP_OFF_4L & _ENHCPU_OFF_4L & _BACKBUG_OFF_4L;
code char at __CONFIG5L CONFIG5L = _CP_0_OFF_5L & _CP_1_OFF_5L & _CP_2_OFF_5L & _CP_3_OFF_5L;
code char at __CONFIG5H CONFIG5H = _CPB_OFF_5H;
code char at __CONFIG6L CONFIG6L = _WRT_0_OFF_6L & _WRT_1_OFF_6L & _WRT_2_OFF_6L & _WRT_3_OFF_6L;
code char at __CONFIG6H CONFIG6H = _WRTC_OFF_6H & _WRTB_OFF_6H;
code char at __CONFIG7L CONFIG7L = _EBTR_0_OFF_7L & _EBTR_1_OFF_7L & _EBTR_2_OFF_7L & _EBTR_3_OFF_7L;
code char at __CONFIG7H CONFIG7H = _EBTRB_OFF_7H;


  --Autor: Miguel Montiel Martinez
 * Las lineas se agregan el 28 de agosto de 2012
 * Se redefine la funcion lcd_send_quartet para que pueda enviar info son solo
 * 3 terminales, las cuales pueden ser cualquiera, derivada de la libreria
 * para CCS
 *
 * //Modificación de Flex_lcd por Duende_Azul y Akenafab
    //Trabaja con 3 pines y 74VHC164
    //8-Bit Serial-In, Parallel-Out Shift Register

    //La LCD se usa en modo 4bits
    //Revisar diagrama de conexion Adjunto
    //Se ha utilizado a una velocidad de @40MHz sin ningun problema

    //No esta habilitada la lectura del LCD
    //RW debe ir a gnd

    //Definir pines antes de llamar libreria//
    //#define LCD_E    PIN_A0
    //#define LCD_CK    PIN_A1
    //#define LCD_DAT  PIN_A2
 * No se define una licencia
 * disponible la version original en http://www.todopic.com.ar/foros/index.php?topic=27011.0
 * \endverbatim
 */

#define LCD_CLEAR                0x01 // Clear Display
#define LCD_HOME                0x02 // Cursor a Home
#define LCD_NORMAL              0x06 // Cursor en modo incrementar.
#define LCD_REV                  0x04 // Normal-reverse
#define LCD_SCROLL              0x07 // Usa scroll
#define LCD_SCROLL_REV          0x05 // Reverse
#define LCD_D8_BIT              0x38 // 8 bit 2 lineas ( 5x7 font )
#define LCD_D4_BIT_CONF          0x20 // 4 bit
#define LCD_D4_BIT              0x28 // 4 bit 2 lineas ( 5x7 font )
#define LCD_RESET                0x30 // Reset
#define LCD_DIS_ON              0x0C // Display on modo 2 lineas
#define LCD_DIS_OFF              0x08 // Display off
#define LCD_LINE1                0x80 // Linea 1 posicion 1 1000 0000
#define LCD_LINE2                0xC0 // Linea 2 posicion 1 1010 0000
#define LCD_LINE3        0x94 //Linea 3 posicion  1
#define LCD_LINE4        0xD4 //Linea 4 posicion  1
#define LCD_CURSOR_ON            0x0E // Cursor on
#define LCD_CURSOR_OFF          0x0C // Cursor off
#define LCD_BLINK_ON            0x0F // Cursor blink
#define LCD_CURSOR_DER          0x14 // Mover cursor derecha
#define LCD_CURSOR_IZQ          0x10 // Mover cursor izquierda
#define LCD_DISPLAY__DER        0x1C // Scroll display derecha
#define LCD_DISPLAY__IZQ        0x18 // Scroll display izquierda
#define LCD_CHARMODE            0x01 //envia caracter
#define LCD_COMMANDMODE          0x00 //envia comando
#define LCD_CGRAM1        0x40 //primera direccion para CGRAM
#define LCD_CGRAM2        0x48 //segunda direccion para CGRAM


/** Seccion de funciones
 *  En esta seccion se encuentran las funciones necesarias para implementar
 *  la interfaz entre una pantalla LCD y un microcontrolador PIC18
 */

//Cadena para enviar la inicializacion de la LCD
const char LCD_INIT_STRING[]=
{
    LCD_D4_BIT, LCD_CLEAR, LCD_CURSOR_OFF, LCD_NORMAL,
    LCD_DIS_ON
};

/**
 * @brief
 *  void lcd_send quartet
 *  Esta función permite el envio de un nibble a través de las terminales
 *  definidas como salidas, requiere de los parametros
 * @param mode Se requiere indicar si es un comando o un caracter el que se
 *              envia
 * @param dato Aquí se coloca el dato a enviar a la LCD
 */

void lcd_send_quartet(char mode, char dato)
{
    unsigned char temp=0;
    unsigned char mask=0;
    unsigned char x=0;
    unsigned char rs_pin;

    rs_pin = mode;

    if(rs_pin == 1)
        dato |= 0x08;

    for(x=0;x<5;x++)
    {
        temp = dato;
        mask = 0x01;
        if(x<4)
        {
            mask = mask <<(x +4);
            mask &= 0xf0;
        }
        else
        {
            mask = 0x08;
        }

        temp &= mask;
        if(mask == 0x08) temp= temp >> 3;
        else temp = temp >> (x + 4);
        temp &= 0x01;
        DAT_PIN = temp;
        CK_PIN = 0;
        delay_ms(2);
        CK_PIN = 1;
        delay_ms(2);
    }

    E_PIN = 1;
    delay_ms(1);
    E_PIN = 0;
}




/**
 * @brief void lcd_send(char mode char dato)
 * @param mode parametro para diferenciar entre comando o dato
 * @param dato dato o comando a enviar
 */

void lcd_send(char mode, char dato)
{
    unsigned char temp;
            delay_ms(1);
            E_PIN = 0;

            temp = dato;
            temp &= 0xf0;
            lcd_send_quartet(mode, temp);
            temp = dato;
            temp = temp <<4;
            temp &=0xf0;
            lcd_send_quartet(mode, temp);


}
/**
 * @brief lcd_init()  funcion para inicializar la LCD
 */
void lcd_init(void)
{
    unsigned char i;

    TRIS_E = 0;
    TRIS_CK = 0;
    TRIS_DAT= 0;
    E_PIN = 0;

    delay_ms(15);


    for(i=0; i< 3; i++)
    {
        lcd_send_quartet(LCD_COMMANDMODE, LCD_RESET);
        delay_ms(5);
    }

    lcd_send_quartet(LCD_COMMANDMODE, LCD_D4_BIT_CONF);
    delay_ms(5);

    for(i=0; i < sizeof(LCD_INIT_STRING); i++)
    {
        lcd_send(LCD_COMMANDMODE, LCD_INIT_STRING[i]);
        delay_ms(5);


    }

}

/**
 * @brief
 * funcion para posicionar el cursor del LCD en un localidad (x,y) particular
 * la funcion esta preparada para trabajar con una LCD de 20 x 4
 * @param x columna del lcd
 * @param y fila del LCD
 */
void lcd_gotoxy(unsigned char x, unsigned char y)
{
    unsigned char ADDRESS= 0x00;

    switch(y)
    {
        case 1:
            ADDRESS  = LCD_LINE1;
            break;
        case 2:
            ADDRESS = LCD_LINE2;
            break;
        case 3:
            ADDRESS = LCD_LINE3;
            break;
        case 4:
            ADDRESS = LCD_LINE4;
            break;
        default:
            ADDRESS = LCD_LINE1;
            break;

    }
    ADDRESS = (ADDRESS + x) -1;
    lcd_send(LCD_COMMANDMODE, ADDRESS);
}

/**
 * @brief
 * Funcion que envia un caracter a la lcd o puede enviar caracteres especiales
 * @param c caracter a enviar
 * Si \f se limpia la LCD
 * Si \n es avance de linea
 * Si \b se envia un retroceso
 */
void lcd_putc( char c)
{
    char lcd_line = 1;
    if(c == 'ñ') c= 0xee;//ñ
    if(c == 'º') c=0xdf;//º
    switch(c)
    {

        case '\f':
            lcd_send(LCD_COMMANDMODE, LCD_CLEAR);
            break;
        case '\n':
            lcd_gotoxy(1,++lcd_line);
            break;
        case '\b':
            lcd_send(LCD_COMMANDMODE, LCD_CURSOR_IZQ);
            break;
        default:
            lcd_send(LCD_CHARMODE,c);
            break;
    }
}



/**
 * @brief
 * Funcion que permite personalizar la presntacion del cursor en el LCD
 * @param visible
 * @param blink
 *
 * Si visible  = 1, el cursor estará visible
 * Si blink = 1, el cursor estará parpadeante
 */
void lcd_setcursor_vb(unsigned char visible, unsigned char blink)
{
    lcd_send(LCD_COMMANDMODE, LCD_DIS_ON | (visible << 1) | blink);
}

/**
 * @brief
 * La funcion puts pone en cola de impresion a lcd una cadena de caracteres
 * @param ptr Puntero de la cadena, el cual va señalando el turno de caracter
 * para ser impreso
 */
void lcd_puts(char * ptr)
{
    while(*ptr)
    {
        lcd_putc( *ptr);
        ptr++;
    }
}

char lcd_hexa(char a)
{
    if(a > 9)
        a+= 55;
    else
        a+= 48;
    return a;
}



#endif // fLCD3bSDCC_h
